java分为简单数据类型和复合类型,简单类型为整数,浮点,字符,布尔;复合类型为类,接口,数组。
简单类型传参是值传递,复合类型是引用传递
静态代码块在类被装载时执行,且只执行一次。通常用来做初始化
覆写:方法名,参数,返回类型都相同
重载:方法名相同,参数不同
重载是同一个类中不同的方法,覆写是子类和父类中相同方法的不同实现
抽象类中如果有抽象方法,则具体子类必须对其进行覆写
接口的实现类必须覆写接口的全部抽象方法
方法前有final修饰则不能在子类覆写
抽象类:用abstract修饰的类,不能创建对象,可以声明并引用其子类对象,非抽象方法可以调用抽象方法,抽象子类不能有父类同名的抽象方法,abstract不能和final修饰同一个类,不能和private,static,final,native修饰同一个方法
接口:方法说明的集合,也可以继承父接口。
抽象类有构造方法,接口没有
抽象类可以有抽象方法和非抽象方法,接口只有抽象方法,且不需要abstract修饰,即为等效
一个类只能继承一个父类,但可以实现多个接口
public StringBuffer append(String s)
将指定的字符串追加到此字符序列。
public StringBuffer reverse()
将此字符序列用其反转形式取代。
public delete(int start, int end)
移除此序列的子字符串中的字符。
public insert(int offset, int i)
将 int 参数的字符串表示形式插入此序列中。
insert(int offset, String str)
将 str 参数的字符串插入此序列中。
replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符
String substring(int start[, int end])
返回一个新的 String,它包含此序列当前所包含的字符子序列。
/,不要用.继承Thread类
public MyThread extends Thread{
public void run(){}
public static void main(String args){
new MyThread().start();
}
}
实现Runnable接口
public MyThread implements Runnable{
public void run(){}
public static void main(String args){
new Thread(new MyThread()).start();
}
}
创建类对象时作为参数传入成员属性
保证它修饰的方法或者代码块任意时刻只有一个线程在访问。
三种用法:
synchronized(要加锁的变量){//对代码块加锁
代码块
}
public synchronized void add(){//对方法加锁
方法体
}
volatile保证不同线程对共享变量操作的可见性,也就是说一个线程修改了volatile修饰的变量,当修改写回主内存时,另外一个线程立即看到最新的值。
volatile只能修饰变量,且多线程访问时不会出现阻塞;而synchronized可以修饰变量,代码块,方法;synchronized可以保证原子性,常用于操作同步,volatile常用于保证变量可见性。
public final void setName(String name)
改变线程名称,使之与参数 name 相同。
public final void setPriority(int priority)
更改线程的优先级。
notifyAll()
唤醒等待资源的所有线程
wait()
线程等待
反射机制允许程序在执行期借助于 ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
加载完类之后,在堆中就产生了ー个 Classe类型的对象(一个类只有一个 Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个 Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射
相关主要类
java.lang.Class:代表一个类, Class对象表示某个类加载后在堆中的对象
java.lang.reflect.Method:代表类的方法, Method对象表示某个类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
eg.
//读配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("code\\t26_reflection\\class.properties"));
String classpath = properties.get("classpath").toString();
String method = properties.get("method").toString();
//反射机制获得类调方法
Class aClass = Class.forName(classpath);
//获得要加载的类的对象实例
Object o = aClass.newInstance();
//o的运行类型
System.out.println(o.getClass());
//java.lang.reflect.Method:代表类的方法, Method对象表示某个类的方法
Method method1 = aClass.getMethod(method);
//方法.invoke(对象)来调用方法
method1.invoke(o);
//java.lang.reflect.Field:代表类的成员变量
//getField不能得到私有属性
Field numField = aClass.getField("num");
//成员变量对象.get(对象)
System.out.println(numField.get(o));
//java.lang.reflect.Constructor:代表类的构造方法
//可以指定构造器参数类型
Constructor constructor = aClass.getConstructor(int.class);
Object o1 = constructor.newInstance(1);
method1.invoke(o1);
反射调用优化:关闭访问检查
Method和 Field、 Constructor对象都有 setAccessible()方法
setAccessible作用是启动和禁用访问安全检查的开关
参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为 false则表示反射的对象执行访问检查
Class类常用方法
在不同阶段拿到Class类对象
类加载
通过反射获取类的结构信息
反射构造对象
当构造器私有时,可以用getDeclearedConstructor(形参class)获取构造器,对构造器使用setAccessable(true)暴破
此时可以用该私有构造器构造对象
反射访问类中成员
在一个类内定义一个类
public class A{
修饰符 class B{
}
}
访问特点
1.内部类可以直接访问外部类的成员,包括私有
2.外部类要访问内部类的成员必须先创建对象
在类的成员位置
在外界调用(仅限内部类为public)
Outer.Inner a = new Outer().new Inner();
外部类内可以调用private内部类,故可以用外部类的方法调内部类
定义在方法中,外界无法直接调用,需要在方法内创建对象使用。局部内部类可以访问外部类的成员和方法内的变量
public class Outer {
private int num = 10;
public void method(){
int num2 = 20;
class Inner {
public void show(){
System.out.println(num);
System.out.println(num2);
}
}
}
}
一个继承了某类或实现了某接口的子类匿名对象
public class Outer {
public void method(){
new Inter(){
@Override
public void method() {
System.out.println("inner");
}
};
}
}
格式:
try{
可能出现异常的代码
}catch(异常类名 变量名){
异常处理代码
}finally{
最终执行代码
}
e.printStackTrace():把异常的错误信息输出在控制台
e.toString():返回简短描述
e.getMessage():返回此throwable的详细消息字符串
格式
throws 异常类名
跟在方法的括号后面
编译时异常必须要进行处理,如果用throws将来谁调用谁处理
运行时异常可以不处理,出现问题后需要修改代码
定义一个类继承Exception
添加无参和带参构造
super(msg);
使用时可以在throw新异常类对象时带参,表示问题
入门
IO,即in和out,也就是输入和输出,指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。
Java 中是通过流处理IO 的,那么什么是流?
流(Stream),是一个抽象的概念,是指一连串的数据(字符或字节),是以先进先出的方式发送信息的通道。
当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。
一般来说关于流的特性有下面几点:
IO流分类
按数据流方向:输入流、输出流
读取文件是输入流,写文件是输出流
按处理数据单位:字节流、字符流
字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。用一句话说就是:字节流可以处理一切文件,而字符流只能处理纯文本文件。
按功能:节点流、处理流(缓冲字节流)
节点流:直接操作数据读写的流类,比如FileInputStream
处理流:对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能,例如BufferedInputStream(缓冲字节流)
IO流对象
File类
File类是用来操作文件的类,但不能操作文件里的数据
构造方法
| 方法名 | 说明 |
|---|---|
| File(File parent, String child) | 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。 |
| File(String pathname) | 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 |
| File(String parent, String child) | 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 |
| File(URI uri) | 通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。 |
常用方法
| 方法 | 说明 |
|---|---|
| createNewFile() | 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 |
| delete() | 删除此抽象路径名表示的文件或目录。 |
| exists() | 测试此抽象路径名表示的文件或目录是否存在。 |
| getAbsoluteFile() | 返回此抽象路径名的绝对路径名形式。 |
| getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串。 |
| length() | 返回由此抽象路径名表示的文件的长度。 |
| mkdir() | 创建此抽象路径名指定的目录。 |
使用示例
public class FileTest {
public static void main(String[] args) throws IOException {
File file = new File("C:/Mu/fileTest.txt");
// 判断文件是否存在
if (!file.exists()) {
// 不存在则创建
file.createNewFile();
}
System.out.println("文件的绝对路径:" + file.getAbsolutePath());
System.out.println("文件的大小:" + file.length());
// 刪除文件
file.delete();
}
}
字节流
InputStream实现子类
字符流
Reader实现子类
IO流方法
字节流方法
字节输入流InputStream()主要方法
字节输出流OutputStream主要方法
字符流方法
字符输入流Reader主要方法
字符输出流Writer主要方法
字符缓冲流方法
入门
三要素
ip地址
端口
协议
UDP
TCP
传输控制协议
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
第一次握手,客户端向服努器端发岀连接请求,等待服器确认
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
第三次握手,客户端再次向肜务器端发送确认信息,确认连接
InetAddress类使用
| 方法名 | 说明 |
|---|---|
| static InetAddress getByName(String host) | 确定主机名称的ip地址。主机名称可以是机器名称也可以是ip地址 |
| String getHostName() | 获取此ip地址的主机名 |
| String getHostAddress() | 返回文本显示中的ip地址字符串 |
UDP通信程序
UDP发送数据
创建发送端Socket对象(DatagramSocket)
创建数据,并把数据打包(DatagramPacket)
调用DatagramSocket对象的方法发送数据
关闭发送端
import java.io.IOException;
import java.net.*;
public class UdpTest1 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
byte[] bytes = "hello".getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 25565);
ds.send(packet);
ds.close();
}
}
UDP接收数据
创建接收端的Socket对象(DatagramSocket)
创建一个数据包,用于接收数据
调用DatagramSocket对象的方法接收数据
解析数据包,并把数据在控制台显示
关闭接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpTest2 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(25565);
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes,bytes.length);
socket.receive(packet);
String info = new String(packet.getData(), 0, packet.getLength());
System.out.println(info);
socket.close();
}
}
TCP通信程序
TCP通信原理:TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个 Socket时象,从而在通信的两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。Java对基于TCP协议的的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过 Socket产生IO流来进行网络通信。Java为客户端提供了 Socket类,为服务器端提供了 ServerSocket类
TCP发送数据
创建客户端的Socket对象
获取输出流,写数据
释放资源
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TcpTest1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 20000);
OutputStream os = socket.getOutputStream();
os.write("hello".getBytes());
os.close();
}
}
TCP接收数据
创建服务端的Socket(ServerSocket)
获取输入流,读数据
释放资源
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpTest2 {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(20000);
Socket socket1 = socket.accept();
InputStream is = socket1.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
String s = new String(bytes, 0, len);
System.out.println(s);
}
}
Swing如果要做实时更新消息,可以用SwingWorker开线程
Lambda 表达式主要用来定义行内执行的方法类型接口
格式:
(parameters) -> expression或(parameters) ->{ statements; }
lambda 表达式只能引用标记了 final 的外层局部变量,不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
public static void main(String args[]) {
final int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2); // 输出结果为 3
}
public interface Converter<T1, T2> {
void convert(int i);
}
package com.runoob.main;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
class Car {
//Supplier是jdk1.8的接口,这里和lamda一起使用了
public static Car create(final Supplier<Car> supplier) {
return supplier.get();
}
public static void collide(final Car car) {
System.out.println("Collided " + car.toString());
}
public void follow(final Car another) {
System.out.println("Following the " + another.toString());
}
public void repair() {
System.out.println("Repaired " + this.toString());
}
}
构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
静态方法引用:它的语法是Class::static_method,实例如下:
cars.forEach( Car::collide );
特定类的任意对象的方法引用:它的语法是Class::method实例如下:
cars.forEach( Car::repair );
特定对象的方法引用:它的语法是instance::method实例如下:
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Predicate 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。
该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)。
该接口用于测试对象是 true 或 false。
我们可以通过以下实例来了解函数式接口 Predicate 的使用:
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Java8Tester {
public static void main(String args[]){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// Predicate<Integer> predicate = n -> true
// n 是一个参数传递到 Predicate 接口的 test 方法
// n 如果存在则 test 方法返回 true
System.out.println("输出所有数据:");
// 传递参数 n
eval(list, n->true);
// Predicate<Integer> predicate1 = n -> n%2 == 0
// n 是一个参数传递到 Predicate 接口的 test 方法
// 如果 n%2 为 0 test 方法返回 true
System.out.println("输出所有偶数:");
eval(list, n-> n%2 == 0 );
// Predicate<Integer> predicate2 = n -> n > 3
// n 是一个参数传递到 Predicate 接口的 test 方法
// 如果 n 大于 3 test 方法返回 true
System.out.println("输出大于 3 的所有数字:");
eval(list, n-> n > 3 );
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for(Integer n: list) {
if(predicate.test(n)) {
System.out.println(n + " ");
}
}
}
}
接口可以有实现方法,而且不需要实现类去实现其方法。
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
// 静态方法
static void blowHorn(){
System.out.println("按喇叭!!!");
}
}
一个接口有默认方法,考虑这样的情况,一个类实现了多个接口,且这些接口有相同的默认方法,以下实例说明了这种情况的解决方法:
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
}
public interface FourWheeler {
default void print(){
System.out.println("我是一辆四轮车!");
}
}
第一个解决方案是创建自己的默认方法,来覆盖重写接口的默认方法:
public class Car implements Vehicle, FourWheeler {
default void print(){
System.out.println("我是一辆四轮汽车!");
}
}
第二种解决方案可以使用 super 来调用指定接口的默认方法:
public class Car implements Vehicle, FourWheeler {
public void print(){
Vehicle.super.print();
}
}
Stream是一个来自数据源的元素队列并支持聚合操作。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。

特性:
在 Java 8 中, 集合接口有两个方法来生成流:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。